#  This is part of the Scopia data visualization example collection
#
#
#  Copyright (C) 2008  Scopia Visual Interfaces Systems 
#                      http://www.scopia.es
#
#  author: Alejandro Conty
#  contributors:
#
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.
from scopiavf.engine.rendertree import *
from chart import *
import scopiavf.engine.interactive as interactive
from timeslider import TimeSlider

class CommonSharesControl(object):
    """Common control values for the whole "widget" """
    # time position of the time window (center)
    timePos = 0.0
    # aperture of the time window
    timeRadius = 1.0

    def __init__(self, tpos, tradius):
        self.timePos = tpos
        self.timeRadius = tradius

class SharesMainNode(RenderOrthoNode):
    """Root scene node for the shares "widget". Composes all the needed scene nodes
       and puts them under an ortho projection"""

    def __init__(self, context, style, mychart):
        self.chart = mychart
        self.timeMin = mychart.transactions[0][V_TIME]
        self.timeMax = mychart.transactions[-1][V_TIME]
        self.timeTotal = mychart.transactions[-1][V_TIME] - mychart.transactions[0][V_TIME]
        # create common control values
        self.common = CommonSharesControl( mychart.transactions[0][V_TIME], self.timeTotal / 16.0 )
        # "players" circle node
        self.shares = SharesCircle( context, style, mychart, self.common)
        # labels for players, another node
        sharelabels = SharesCircleLabels( context, style, mychart)
        # compose together both the circle and the labels
        sharescomp = RenderComposeNode( context, style, [sharelabels, self.shares] )
        # then put it under a transform for moving and scaling it a bit
        sharesT = RenderSimpleTransformNode( context, style, sharescomp )
        sharesT.set( (0, 0.15, 0), (0.9, 0.9, 1) )
        # create the timeline and put it under another transform
        self.timeline = TimeSlider( context, style, mychart, self.common, [self.shares] )
        timelineT = RenderSimpleTransformNode( context, style, self.timeline)
        timelineT.set( (0, -0.8, 0), (1, 1, 1) )
        # finally compose both the circle with labels and the timeline
        wcomp = RenderComposeNode( context, style, [sharesT, timelineT] )
        # call constructor with the last compose as child of the projection
        RenderOrthoNode.__init__(self, context, style, wcomp, (0,0), (1,1))

class SharesCircle(RenderGeomNode):
    """Scene node for the circle of "players" """
    def __init__(self, context, style, mychart, common):
        "Build from a chart and common control values"
        RenderGeomNode.__init__(self, context, style)
        self.common = common
        self.chart = mychart
        # calculate angle interval for every player based on its volume and 
        # save it in playertoangle dict
        asizes = array( [ players[idx].volume for idx in mychart.players ], 'f' )
        asizes *= 2.0*math.pi/sum(asizes)
        playertoangle = {}
        angle1 = 0.0
        for i, a in enumerate(mychart.players):
            angle2 = angle1 + asizes[i]
            playertoangle[a] = ( angle1, angle2 )
            angle1 = angle2
        self.playertoangle = playertoangle

    def renderAll(self):
        # From the chart, and given a timewindow, we get the data to draw:
        #    transactions:    transactions in this timewindow
        #    status:    share count average of every player in this timewindow
        #    delta:     number of shares moved per time unit for every player
        #    deltadir:  direction of the movement (0.0 outgoing, 1.0 incoming) for every player
        transactions, status, delta, deltadir, W = self.chart.getWindow( self.common.timePos - self.common.timeRadius, self.common.timePos + self.common.timeRadius )
        # draw circle and "transactions" (transactions) curves
        self.style.drawPlayers( self.context, self, status, delta, deltadir )
        self.style.drawTransactions( self.context, self, transactions, W )

class SharesCircleLabels(RenderGeomNode):
    """Scene node with the labels for players in the circle"""
    def __init__(self, context, style, mychart):
        RenderGeomNode.__init__(self, context, style)
        self.chart = mychart
        # how can we avoid calculating this here again ?
        asizes = array( [ players[idx].volume for idx in mychart.players ], 'f' )
        asizes *= 2.0*math.pi/sum(asizes)
        playertoangle = {}
        angle1 = 0.0
        for i, a in enumerate(mychart.players):
            angle2 = angle1 + asizes[i]
            playertoangle[a] = ( angle1, angle2 )
            angle1 = angle2
        self.playertoangle = playertoangle

    def renderAll(self):
        self.style.drawPlayerNames( self.context, self )

